package com.mosai.alignpro;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.recyclerview.widget.RecyclerView;

import com.alibaba.fastjson.JSON;
import com.mosai.alignpro.adapter.DiagnosisListAdapter;
import com.mosai.alignpro.api.API;
import com.mosai.alignpro.api.HttpUtils;
import com.mosai.alignpro.entity.DoctorInfo;
import com.mosai.alignpro.entity.ImageInfo;
import com.mosai.alignpro.entity.LastParam;
import com.mosai.alignpro.entity.ListData;
import com.mosai.alignpro.entity.RnDiagnosisListParam;
import com.mosai.alignpro.event.AuditEvent;
import com.mosai.alignpro.event.EditingEvent;
import com.mosai.alignpro.event.PatientImageEvent;
import com.mosai.alignpro.event.RNEvent;
import com.mosai.alignpro.util.DataUtils;
import com.mosai.alignpro.util.DialogUtils;
import com.mosai.alignpro.util.IntentUtils;
import com.mosai.alignpro.util.LogUtils;
import com.mosai.alignpro.util.ToastUtils;
import com.mosai.alignpro.view.DiagnosisHistoryDialog;
import com.mosai.alignpro.view.MyLinearLayoutManager;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.Collections;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

/**
 * 诊断列表
 * Created by Rays on 2020/3/9.
 */
public class DiagnosisListActivity extends BaseActivity {
    private static final String TAG = DiagnosisListActivity.class.getSimpleName();

    public static final String EXTRA_DATA = "data";
    public static final String EXTRA_IMAGE_INFO = "imageInfo";
    public static final String EXTRA_DOCTOR_INFO = "doctorInfo";
    public static final String EXTRA_IS_CAN_CONFIRM = "isCanConfirm";

    private TextView tvTitle, tvHistory;
    private RecyclerView recyclerView;
    private MyLinearLayoutManager layoutManager;
    private boolean isEditing, isHistory, isLoadMore, isAssistant, isCanConfirm;
    private DiagnosisListAdapter adapter;
    private int currentPosition;
    private LastParam lastParam = new LastParam();
    private RnDiagnosisListParam param;
    private DoctorInfo doctorInfo;
    private long lastHintTime;

    public static void startHistory(Activity activity, ImageInfo info, DoctorInfo doctorInfo, boolean isCanConfirm) {
        Intent intent = new Intent(activity, DiagnosisListActivity.class);
        intent.putExtra(EXTRA_IMAGE_INFO, info);
        intent.putExtra(EXTRA_DOCTOR_INFO, doctorInfo);
        intent.putExtra(EXTRA_IS_CAN_CONFIRM, isCanConfirm);
        activity.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_diagnosis_list);
        initView();
        EventBus.getDefault().register(this);
    }

    private void initView() {
        tvTitle = findViewById(R.id.tvTitle);
        if (IntentUtils.isPatientApp()) {
            tvTitle.setText(R.string.diagnosis_title_patient_app);
        }
        tvHistory = findViewById(R.id.tvHistory);

        recyclerView = findViewById(R.id.recyclerView);
        layoutManager = new MyLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);

        PagerSnapHelper pagerSnapHelper = new PagerSnapHelper() {
            @Override
            public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
                int targetSnapPosition = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
                loadMore(targetSnapPosition);
                return targetSnapPosition;
            }

            @Nullable
            @Override
            public View findSnapView(RecyclerView.LayoutManager layoutManager) {
                View snapView = super.findSnapView(layoutManager);
                if (snapView != null) {
                    int currentPosition = (int) snapView.getTag();
                    LogUtils.d(TAG, "findSnapView currentPosition: " + currentPosition);
                    setCurrentPosition(currentPosition);
                }
                return snapView;
            }
        };
        pagerSnapHelper.attachToRecyclerView(recyclerView);

        recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int width = recyclerView.getWidth();
                int height = recyclerView.getHeight();
                LogUtils.i(TAG, "onGlobalLayout"
                        + " width: " + width
                        + " height: " + height
                        + " adapter: " + recyclerView.getAdapter()
                );
                recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                setAdapter(width, height);
            }
        });
    }

    private void scrollToPosition(int position) {
        recyclerView.scrollToPosition(position);
        setCurrentPosition(position);
    }

    private void setCurrentPosition(int position) {
        currentPosition = position;
        LogUtils.d(TAG, "setCurrentPosition currentPosition: " + currentPosition);
        showOrHideHistory();
    }

    public ImageInfo getImageInfo() {
        int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
        LogUtils.d(TAG, "getImageInfo"
                + " currentPosition: " + currentPosition
                + " firstVisibleItemPosition: " + firstVisibleItemPosition
        );
        return getImageInfo(currentPosition);
    }

    public ImageInfo getImageInfo(int position) {
        if (adapter != null && position < adapter.getData().size()) {
            return adapter.getData().get(position);
        }
        return null;
    }

    private void showOrHideHistory() {
        ImageInfo imageInfo = getImageInfo();
        boolean b = isEditing || imageInfo == null || !(imageInfo.isAudited() || (imageInfo.getHistories() != null && !imageInfo.getHistories().isEmpty()));
        tvHistory.setVisibility(b ? View.GONE : View.VISIBLE);
        read(imageInfo);
    }

    private void read(ImageInfo imageInfo) {
        if (imageInfo == null) {
            return;
        }
        if (IntentUtils.isPatientApp() && !imageInfo.isPatientIsRead()) {
            addDisposable(API.patientRead(imageInfo).subscribe(imageInfo1 -> {
            }, API.ON_ERROR));
        }
    }

    private void setAdapter(int width, int height) {
        if (adapter != null) {
            return;
        }
        adapter = new DiagnosisListAdapter(DiagnosisListActivity.this, width, height);

        Intent intent = getIntent();
        if (intent.hasExtra(EXTRA_IMAGE_INFO)) {
            isHistory = true;
            ImageInfo info = (ImageInfo) intent.getSerializableExtra(EXTRA_IMAGE_INFO);
            setCurrentDoctor((DoctorInfo) intent.getSerializableExtra(EXTRA_DOCTOR_INFO));
            isCanConfirm = intent.getBooleanExtra(EXTRA_IS_CAN_CONFIRM, false);
            List<ImageInfo> data = Collections.singletonList(info);
            setAdapter(data);
            return;
        }
        String jsonData = intent.getStringExtra(EXTRA_DATA);
        LogUtils.i(TAG, "jsonData: " + jsonData);
        if (TextUtils.isEmpty(jsonData)) {
            finish();
            return;
        }
        addDisposable(Observable.just(jsonData)
                .observeOn(Schedulers.computation())
                .map(this::handleRnParam)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(param -> setAdapter(param.getListData().getItems()), API.ON_ERROR));
    }

    private RnDiagnosisListParam handleRnParam(String jsonData) {
        param = DataUtils.getRnDiagnosisListParam(this, jsonData);
        isCanConfirm = param.isCanConfirm();
        List<ImageInfo> items = param.getListData().getItems();
        lastParam = param.getLastParam();
        lastParam.setSkipCount(items.size());
        lastParam.setTotalCount(param.getListData().getTotalCount());

        setCurrentDoctor(param.getDoctorInfo());
        for (ImageInfo item : items) {
            if (IntentUtils.isDoctorApp() && item.getDoctorInfo() == null) {
                item.setDoctorInfo(param.getDoctorInfo());
            }
            if (item.getPatientInfo() == null) {
                item.setPatientInfo(param.getPatientInfo());
            }
            item.init();
        }
        HttpUtils.getInstance().setHttpHeader(param.getHttpHeader());
        return param;
    }

    private void setCurrentDoctor(DoctorInfo doctorInfo) {
        this.doctorInfo = doctorInfo;
        isAssistant = IntentUtils.isDoctorApp() && doctorInfo != null && doctorInfo.isAssistant();
    }

    private void setAdapter(List<ImageInfo> data) {
        adapter.setCanConfirm(isCanConfirm);
        adapter.setAssistant(isAssistant);
        adapter.setTotalCount(lastParam.getTotalCount());
        adapter.setData(data);
        recyclerView.setAdapter(adapter);
        if (param != null) {
            scrollToPosition(param.getIndex());
        } else {
            showOrHideHistory();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onPatientImageEvent(PatientImageEvent event) {
        ImageInfo imageInfo = getImageInfo();
        if (event.imageInfo == null || event.imageInfo.getPatientInfo() == null || imageInfo == null
                || event.imageInfo.getImageId() != imageInfo.getImageId()) {
            return;
        }
        imageInfo.setPatientInfo(event.imageInfo.getPatientInfo());
        imageInfo.setPatientId(event.imageInfo.getPatientInfo().getId());
        adapter.notifyItemChanged(currentPosition);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEditingEvent(EditingEvent event) {
        isEditing = event.isEditing;
        layoutManager.setInterceptScroll(isEditing);
        tvTitle.setText(getString(isEditing ? R.string.diagnosis_title_editing : R.string.diagnosis_title_detail));
        showOrHideHistory();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onAuditEvent(AuditEvent event) {
        final ImageInfo info = getImageInfo(event.position);
        if (info == null) {
            return;
        }
        LogUtils.i(TAG, "onAuditEvent");
        showLoadingDialog();
        Observable<ImageInfo> observable = event.isAudit ? API.auditImage(info) : API.editImage(info);
        addDisposable(observable
                .subscribe(res -> {
                    if (doctorInfo != null) {
                        res.setDoctorInfo(doctorInfo);
                    }
                    adapter.getData().set(event.position, res);
                    LogUtils.i(TAG, "res: " + res.getNewDescribe() + " " + JSON.toJSONString(res));
                    LogUtils.i(TAG, "data: " + JSON.toJSONString(adapter.getData()));
                    adapter.notifyItemChanged(event.position);
                    postEvent(new EditingEvent(false));
                }, this::onError, this::dismissLoadingDialog));
    }

    public void onClickBack(View view) {
        if (isEditing) {
            showCancelEditDialog();
            return;
        }
        finish();
    }

    public void onClickHistory(View view) {
        final ImageInfo info = getImageInfo();
        if (info == null) {
            view.setVisibility(View.GONE);
            return;
        }
        showLoadingDialog();
        addDisposable(API.getImageDetail(info).subscribe(this::showDiagnosisHistoryDialog, this::onError, this::dismissLoadingDialog));
    }

    private void showDiagnosisHistoryDialog(ImageInfo detail) {
        new DiagnosisHistoryDialog(this, detail, doctorInfo, isCanConfirm).show();
    }

    private void showCancelEditDialog() {
        DialogUtils.showCancelEditDialog(this, new DialogUtils.OnClickListener() {
            @Override
            protected void onClick(DialogInterface dialog, boolean isPositive) {
                if (isPositive) {
                    getImageInfo().cancelEdit();
                    adapter.notifyItemChanged(currentPosition);
                    postEvent(new EditingEvent(false));
                }
                dialog.dismiss();
            }
        });
    }

    public void loadMore(int position) {
        int i, curSize;
        if (isHistory || isLoadMore || adapter == null
                || (i = (curSize = adapter.getData().size()) - position) > 5
        ) {
            return;
        }
        lastParam.setSkipCount(curSize);
        boolean isLast = i <= 0;
        if (!lastParam.isMore()) {
            if (isLast) {
                showNoMoreData();
            }
            return;
        }
        isLoadMore = true;
        LogUtils.i(TAG, "loadMore"
                + " i: " + i
                + " position: " + position
                + " currentPosition: " + currentPosition
                + " size: " + lastParam.getSkipCount()
        );
        if (isLast) {
            this.showLoadingDialog();
        }
        Observable<ListData> imageList;
        if (IntentUtils.isDoctorApp() && lastParam.isPatientDetailMode()) {
            imageList = API.getPatientImageList(param);
        } else {
            imageList = API.getImageList(param);
        }
        addDisposable(imageList.subscribe(res -> {
            adapter.setTotalCount(res.getTotalCount());
            adapter.add(res.getItems());
            lastParam.setTotalCount(res.getTotalCount());
            int size = adapter.getData().size();
            lastParam.setSkipCount(size);
            adapter.notifyDataSetChanged();

            isLoadMore = false;
            if (isLast) {
                dismissLoadingDialog();
                if (curSize < size) {
                    scrollToPosition(curSize);
                } else {
                    showNoMoreData();
                }
            }
            pendingEmptyFinish();
        }, tr -> {
            isLoadMore = false;
            if (isLast) {
                dismissLoadingDialog();
            }
            API.ON_ERROR_BASE.accept(tr);
        }));
    }

    private void showNoMoreData() {
        if (SystemClock.elapsedRealtime() - lastHintTime > 30000) {
            lastHintTime = SystemClock.elapsedRealtime();
            LogUtils.i(TAG, "lastHintTime: " + lastHintTime);
            ToastUtils.getInstance().show(R.string.msg_no_more_data);
        }
    }

    private void pendingEmptyFinish() {
        if (adapter == null || !adapter.getData().isEmpty()) {
            return;
        }
        DialogUtils.showPendingFinishDialog(this, new DialogUtils.OnClickListener() {
            @Override
            protected void onClick(DialogInterface dialog, boolean isPositive) {
                dialog.dismiss();
                finish();
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) {
            return;
        }
        if (requestCode == EditDescribeActivity.REQUEST_CODE && data != null) {
            ImageInfo imageInfo = getImageInfo();
            if (imageInfo != null) {
                String newDescribe = data.getStringExtra(EditDescribeActivity.EXTRA_DESCRIBE);
                boolean notEditDescribe = TextUtils.equals(newDescribe, imageInfo.getNewDescribe());
                imageInfo.setNewDescribe(newDescribe);
                imageInfo.setNotEditDescribe(notEditDescribe);
                if (data.hasExtra(EditDescribeActivity.EXTRA_SCOLIOSIS_TYPE)) {
                    imageInfo.setNewScoliosisType(data.getIntExtra(EditDescribeActivity.EXTRA_SCOLIOSIS_TYPE, 0));
                    imageInfo.setNewConditionStatus(data.getIntExtra(EditDescribeActivity.EXTRA_CONDITION_STATUS, 0));
                }
                adapter.notifyItemChanged(currentPosition, DiagnosisListAdapter.PAYLOAD_DESCRIBE);
            }
        }
    }

    @Override
    public void onBackPressed() {
        if (isEditing) {
            onClickBack(null);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        if (!isHistory) {
            EventBus.getDefault().post(RNEvent.DIAGNOSIS_LIST_FINISH);
        }
        super.onDestroy();
    }
}
